package io.xxx.omni.osc.sync

import com.suning.api.DefaultSuningClient
import com.suning.api.SuningRequest
import com.suning.api.SuningResponse
import com.suning.api.entity.custom.RefundlistinformationQueryRequest
import com.suning.api.entity.custom.RefundlistinformationQueryResponse
import com.suning.api.entity.transaction.OrderQueryRequest
import com.suning.api.entity.transaction.OrderQueryResponse
import io.xxx.omni.osc.common.dateTimeFormatter
import io.xxx.omni.osc.common.toLocalDateTime
import io.xxx.omni.osc.domain.*
import org.springframework.stereotype.Component
import java.time.LocalDateTime

/**
 * 苏宁
 */
// https://open.suning.com/ospos/apipage/toDocContent.do?menuId=23
// https://open.suning.com/ospos/apipage/toDocContent.do?menuId=53
abstract class SnPorter<T : SuningRequest<R>, R : SuningResponse> : PageDocumentPorter<T, R>(),
    PlatformIdentity.SuNing {

    private val httpUrl = "https://open.suning.com/api/http/sopRequest"

    protected abstract val method: String

    override fun getResponse(context: JobContext, pageNo: Int, hasTotal: Boolean): R {
        val (store, startTime, endTime) = context
        val request = buildRequest(startTime, endTime, pageNo)
        val beanName = "${store.pid}Client${store.id}"
        val client = applicationContext.getBean(beanName, DefaultSuningClient::class.java)
        val response = client.excute(request)
        if (hasError(response)) {
            throwException(context, request, response)
        }
        return response
    }

    protected abstract fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Int,
    ): T

    /**
     * 检查Response，如果Response合法则返回true
     * @return true - Response合法，false - Response不合法
     */
    protected open fun hasError(response: R): Boolean = true
}

// 订单
// https://open.suning.com/ospos/apipage/toApiMethodDetailMenuNew.do?interCode=suning.custom.order.query
@Component
class SnTradePorter : SnPorter<OrderQueryRequest, OrderQueryResponse>() {

    private val noResultCode = "biz.handler.data-get:no-result"

    override val documentType = DocumentType.TRADE

    override val method = "suning.custom.order.query"

    override fun getStartTime(store: Store, jobCheckpoint: JobCheckpoint): LocalDateTime {
        val minStartTime = LocalDateTime.now().minusMonths(2)
        val startTime = jobCheckpoint.endTime
        return if (startTime < minStartTime) minStartTime else startTime
    }

    override fun getCount(context: JobContext, response: OrderQueryResponse): Int =
        if (response.snerror != null) 0 else response.snhead.totalSize.toInt()

    override fun buildDocuments(context: JobContext, response: OrderQueryResponse): List<Document> {
        return response
            .snbody
            .orderQuery
            .map {
                val sn = it.orderCode
                val status = it.orderTotalStatus
                val modified = it.orderSaleTime.toLocalDateTime()
                Document(sn, status, modified, it)
            }
    }

    override fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Int
    ): OrderQueryRequest {
        val request = OrderQueryRequest()
        request.startTime = startTime.format(dateTimeFormatter)
        request.endTime = endTime.format(dateTimeFormatter)
        request.setPageSize(pageSize)
        request.setPageNo(pageNo)
        return request
    }

    override fun hasError(response: OrderQueryResponse): Boolean {
        val error = response.snerror
        return !(error == null || error.errorCode == noResultCode)
    }
}

// 退单
// https://open.suning.com/ospos/apipage/toApiMethodDetailMenuNew.do?interCode=suning.custom.refundlistinformation.query
@Component
class SnRefundPorter : SnPorter<RefundlistinformationQueryRequest, RefundlistinformationQueryResponse>() {

    override val documentType = DocumentType.REFUND

    override val pageSize = 10

    override val method = "suning.custom.refundlistinformation.query"

    override fun getCount(context: JobContext, response: RefundlistinformationQueryResponse): Int {
        return response.snhead.totalSize.toInt()
    }

    override fun buildDocuments(context: JobContext, response: RefundlistinformationQueryResponse): List<Document> {
        return response
            .snbody
            .queryRefundlistinformation
            .flatMap { it.returnList }
            .map {
                val sn = it.returnApplyId
                val rsn = it.orderNo
                val status = it.returnStatusValue
                val modified = it.operateTime.toLocalDateTime()
                Document(sn, rsn, status, modified, it)
            }
    }

    override fun buildRequest(
        startTime: LocalDateTime,
        endTime: LocalDateTime,
        pageNo: Int
    ): RefundlistinformationQueryRequest {
        val request = RefundlistinformationQueryRequest()
        request.startModified = startTime.format(dateTimeFormatter)
        request.endModified = endTime.format(dateTimeFormatter)
        request.setPageSize(pageSize)
        request.setPageNo(pageNo)
        return request
    }

    override fun hasError(response: RefundlistinformationQueryResponse): Boolean {
        val error = response.snerror
        return error != null
    }
}